import json
import re
import time
from io import BytesIO

import requests as req
from PIL import Image

from geetest_crack.my_param import get_full_page_w1, get_full_page_w2, get_slide_w, get_s, get_w2_dy_kv,get_track
from geetest_crack.utils.captcha import calculate_offset
from geetest_crack.utils.times import now_str
from geetest_crack.utils.track_maker import GTrace

get_php_url = 'https://api.geetest.com/get.php'
ajax_php_url = 'https://api.geetest.com/ajax.php'
static_geetest_url = 'https://static.geetest.com/'

common_headers = {
    'Referer': 'https://ss.cods.org.cn/',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
                  'Chrome/79.0.3945.117 Safari/537.36'
}

proxies = {}


# proxies = {'http': 'http://119.191.58.29:5001', 'https': 'http://119.191.58.29:5001'}

class GeeValidate:

    def __init__(self, reg_json_str=str()):
        self.gt = str()
        self.challenge = str()
        self.reg_json_str = reg_json_str

        self.s = get_s()
        self.bg_url = str()
        self.full_bg_url = str()
        self.track = list()
        self.offset = 0
        self.validate = str()
        self.sec_code = str()
        self.get_php_json = str()
        self.get_php_json2 = str()

        self.tracker = GTrace()
        self.ajax_w2_dy_kv = []

    def reset_reg_json_str(self, reg_json_str):
        self.reg_json_str = reg_json_str

    def set_gt_challenge(self):
        reg_json = json.loads(self.reg_json_str)
        self.gt, self.challenge = reg_json['gt'], reg_json['challenge']
        return True

    def get_php(self):
        params = {
            'gt': self.gt,
            'challenge': self.challenge,
            'lang': 'zh-cn',
            'pt': '0',
            'client_type': 'web',
            'w': get_full_page_w1(self.gt, self.challenge, self.s),
            'callback': 'geetest_' + now_str()
        }
        resp = common_request_get(get_php_url, params)
        if 200 == resp.status_code:
            res_json = json.loads(re.search(r'\((.*?)\)', resp.text, re.S).group(1))
            # print('get_php获取的json：', res_json)
            self.get_php_json = res_json
            return True
        else:
            print('无法注册参数s...')
            return False

    def ajax_php(self, step=1, params=None):
        if step == 1:
            params = {
                'gt': self.gt,
                'challenge': self.challenge,
                'lang': 'zh-cn',
                'pt': '0',
                'client_type': 'web',
                'w': get_full_page_w2(self.gt, self.challenge, self.s, self.get_php_json),
                'callback': 'geetest_' + now_str()
            }
        resp = common_request_get(ajax_php_url, params)
        # if step == 1:
        # print('ajax_1: ', resp.text)
        if 200 != resp.status_code:
            print('ajax[%d]请求失败...' % step)
            return False
        if step != 1:
            print('------- 最终验证提交结果：', resp.text)
            ajax2_text = resp.text
            if ajax2_text.find('success') >= 0:
                res_json = json.loads(re.search(r'\((.*?)\)', ajax2_text, re.S).group(1))
                if res_json['success'] != 1:
                    print('验证失败：SLIDE_ERR')
                    return False
                self.validate = res_json['validate']
                self.sec_code = self.validate + '|jordan'
                print(f'计算获取validate值: {self.validate}')
            else:
                return False
        return True

    def get_slide_images(self):
        """获取验证码图片的地址"""
        params = {
            'is_next': 'true',
            'type': 'slide3',
            'gt': self.gt,
            'challenge': self.challenge,
            'lang': 'zh-cn',
            'https': 'true',
            'protocol': 'https://',
            'offline': 'false',
            'product': 'embed',
            'api_server': 'captcha-api.com',
            'isPC': 'true',
            'width': '100%',
            'callback': 'geetest_' + now_str()
        }
        resp = common_request_get(get_php_url, params)
        if resp is None:
            print('获取滑动图片请求失败...')
            return False
        res_str = resp.text
        if res_str.find('fullbg') >= 0:
            res_json = json.loads(re.search(r'\((.*?)\)', res_str, re.S).group(1))
            print('gct_path: ', res_json['gct_path'])
            has_ct = self.calculate_w2_ct(res_json['gct_path'])
            if has_ct is False:
                return False
            # 获得滑动验证码图片的URL(带缺口+不带缺口)
            self.bg_url = static_geetest_url + res_json['bg']
            self.full_bg_url = static_geetest_url + res_json['fullbg']
            # print('滑动验证码图片,bg_url:%s, full_bg_url:%s' % (self.bg_url, self.full_bg_url))
            # 更新gt/challenge
            print(f"更新challenge：{self.challenge} -> {res_json['challenge']}")
            self.gt = res_json['gt']
            self.challenge = res_json['challenge']
            self.get_php_json2 = res_json
            return True
        else:
            print('获取图片信息失败：', res_str)
            return False

    def calculate_w2_ct(self, gct_path):
        gct_url = static_geetest_url[:-1] + gct_path
        resp = common_request_get(gct_url)
        ct_kv = get_w2_dy_kv(resp.text)
        self.ajax_w2_dy_kv = ct_kv
        return ct_kv is not None

    def get_track(self):
        """获取滑动轨迹"""
        resp1 = common_request_get(self.bg_url)
        resp2 = common_request_get(self.full_bg_url)
        if not (resp1 and resp2):
            return False
        img1 = Image.open(BytesIO(resp1.content))
        img2 = Image.open(BytesIO(resp2.content))

        # 计算偏移量
        self.offset = calculate_offset(img1, img2)
        print('计算偏移量:', self.offset)

        # 获取样本轨迹
        # self.track = get_track(self.offset)
        # 动态生成轨迹（1）
        self.track = self.tracker.get_mouse_pos_path(self.offset)[1]
        # 动态生成轨迹（2）
        # self.track = get_track(self.offset)
        # print('获取轨迹：', self.track)
        if self.track is None:
            print('未能获取轨迹！')
            return False
        return self.track is not None

    def slide(self):
        """滑动滑块"""
        params = {
            'gt': self.gt,
            'challenge': self.challenge,
            'lang': 'zh-cn',
            'pt': '0',
            'client_type': 'web',
            'w': get_slide_w(self.gt, self.challenge, get_s(),
                             self.track, self.get_php_json2['c'],
                             self.get_php_json2['s'], self.ajax_w2_dy_kv),
            'callback': 'geetest_' + now_str()
        }
        time.sleep(self.track[-1][-1] / 1000)
        return self.ajax_php(step=2, params=params)

    def run(self):
        # 此处使用and操作符，当有某个请求返回false时，直接终止当前请求链
        return self.set_gt_challenge() \
               and self.get_php() \
               and self.ajax_php() \
               and self.get_slide_images() \
               and self.get_track() \
               and self.slide()

    def get_result(self):
        return [self.challenge, self.validate, self.sec_code]


def common_request_get(url, params=None):
    return req.get(url=url, params=params, headers=common_headers, proxies=proxies)


def common_request_post(url, data):
    return req.post(url=url, data=data, headers=common_headers, proxies=proxies)
